package cn.iocoder.yudao.module.promotion.gift.service.core;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.business.basic.dao.query.CoreQueryWrapper;
import cn.iocoder.yudao.framework.business.basic.pojo.vo.UserSimpleVO;
import cn.iocoder.yudao.framework.business.basic.service.impl.MemberScopeService;
import cn.iocoder.yudao.framework.common.exception.Assertions;
import cn.iocoder.yudao.framework.common.exception.KnownServiceException;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.module.api.member.user.MemberUserApi;
import cn.iocoder.yudao.module.api.promotion.activity.enums.PromotionDiscountTypeEnum;
import cn.iocoder.yudao.module.api.promotion.coupon.enums.CouponTakeTypeEnum;
import cn.iocoder.yudao.module.api.promotion.coupon.enums.CouponTemplateValidityTypeEnum;
import cn.iocoder.yudao.module.api.promotion.gift.enums.GiftBizType;
import cn.iocoder.yudao.module.api.promotion.gift.enums.GiftGiveType;
import cn.iocoder.yudao.module.api.promotion.gift.enums.GiftRecordStatus;
import cn.iocoder.yudao.module.api.trade.delivery.enums.DeliveryTypeEnum;
import cn.iocoder.yudao.module.api.trade.order.TradeOrderApi;
import cn.iocoder.yudao.module.api.trade.order.dto.GiftTradeOrderSaveDTO;
import cn.iocoder.yudao.module.api.trade.order.dto.TradeOrderRespDTO;
import cn.iocoder.yudao.module.api.trade.order.enums.TradeOrderTypeEnum;
import cn.iocoder.yudao.module.api.trade.scan.ScanOrderApi;
import cn.iocoder.yudao.module.api.trade.scan.dto.ScanOrderDTO;
import cn.iocoder.yudao.module.promotion.coupon.dal.dataobject.CouponTemplateDO;
import cn.iocoder.yudao.module.promotion.coupon.service.CouponRecordService;
import cn.iocoder.yudao.module.promotion.coupon.service.CouponTemplateService;
import cn.iocoder.yudao.module.promotion.gift.convert.GiftActivityConvert;
import cn.iocoder.yudao.module.promotion.gift.convert.GiftRecordConvert;
import cn.iocoder.yudao.module.promotion.gift.dao.GiftActivityMapper;
import cn.iocoder.yudao.module.promotion.gift.dao.GiftRecordMapper;
import cn.iocoder.yudao.module.promotion.gift.mq.GiftProducer;
import cn.iocoder.yudao.module.promotion.gift.pojo.bo.GiftRecordCountBO;
import cn.iocoder.yudao.module.promotion.gift.pojo.dto.AppGiftTakeDTO;
import cn.iocoder.yudao.module.promotion.gift.pojo.dto.AppGiftTransferDTO;
import cn.iocoder.yudao.module.promotion.gift.pojo.dto.GiftRecordQueryDTO;
import cn.iocoder.yudao.module.promotion.gift.pojo.po.GiftActivity;
import cn.iocoder.yudao.module.promotion.gift.pojo.po.GiftRecord;
import cn.iocoder.yudao.module.promotion.gift.pojo.vo.GiftRecordVO;
import cn.iocoder.yudao.module.promotion.groupon.pojo.vo.GrouponOrderVO;
import cn.iocoder.yudao.module.promotion.groupon.service.app.AppGrouponOrderService;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.*;

import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.module.api.promotion.ConfigConstants.GROUPON_PACKAGE_ORDER_NO_PREFIX;
import static cn.iocoder.yudao.module.api.trade.ConfigConstants.SCAN_ORDER_NO_PREFIX;
import static cn.iocoder.yudao.module.api.trade.ConfigConstants.TRADE_ORDER_NO_PREFIX;

@Service
@Validated
@Slf4j
public class CoreGiftRecordServiceImpl extends MemberScopeService<GiftRecord, GiftRecordVO, GiftRecordQueryDTO> implements CoreGiftRecordService {
    @Resource
    private GiftRecordMapper giftRecordMapper;
    @Resource
    private GiftActivityMapper giftActivityMapper;

    @Resource
    private GiftProducer giftProducer;

    @Resource
    @Lazy // TODO 延迟加载，避免循环依赖
    private AppGrouponOrderService appGrouponOrderService;
    @Resource
    private CouponTemplateService couponTemplateService;
    @Resource
    private CouponRecordService couponRecordService;

    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private ScanOrderApi scanOrderApi;
    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private TradeOrderApi tradeOrderApi;
    @Resource
    @Lazy // 延迟加载，避免循环依赖
    private MemberUserApi memberUserApi;

    @Override
    protected GiftRecordMapper getInjectedMapper() {
        return giftRecordMapper;
    }

    @Nonnull
    @Override
    protected CoreQueryWrapper<GiftRecord> buildQueryWrapper(GiftRecordQueryDTO param) {
        CoreQueryWrapper<GiftRecord> wrapper = super.buildQueryWrapper(param);
        wrapper.eqIfPresent("gift_activity_id", param.getGiftActivityId());
        wrapper.eqIfPresent("biz_type", param.getBizType());
        wrapper.eqIfPresent("status", param.getStatus());
        return wrapper;
    }

    @Nonnull
    @Override
    protected Map<Long, UserSimpleVO> getUserSimpleMap(Collection<Long> userIds) {
        return memberUserApi.getUserSimpleMap(userIds);
    }

    @Override
    public int getCount(Long userId, @Nullable Integer status) {
        return getInjectedMapper().selectCountByUserIdAndStatus(userId, status);
    }

    @Override
    public Map<Long, Integer> getTakenCount(Long userId, Collection<Long> giftActivityIds) {
        if (userId == null || userId <= 0 || CollUtil.isEmpty(giftActivityIds)) {
            return new HashMap<>();
        }
        // 批量统计指定用户的已领取记录数量
        List<GiftRecordCountBO> list = getInjectedMapper().selectCountByUserId(userId, giftActivityIds);
        return convertMap(list, GiftRecordCountBO::getGiftActivityId, GiftRecordCountBO::getCount);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean pending(Long userId, String tradeNo, Collection<Long> giftActivityIds) {
        Assertions.notEmpty(giftActivityIds, "未获取到赠品活动编号");
        GiftBizType bizType;
        Long bizOrderId;
        if (tradeNo.startsWith(SCAN_ORDER_NO_PREFIX)) {
            bizType = GiftBizType.OFFLINE_SCAN_ORDER;
            ScanOrderDTO order = scanOrderApi.getByTradeNo(tradeNo);
            Assertions.notNull(order, "未获取到线下扫码订单信息：" + tradeNo);
            bizOrderId = order.getId();
        } else if (tradeNo.startsWith(TRADE_ORDER_NO_PREFIX)) {
            TradeOrderRespDTO order = tradeOrderApi.getByTradeNo(tradeNo);
            Assertions.notNull(order, "未获取到交易订单信息：" + tradeNo);
            Assertions.equals(order.getType(), TradeOrderTypeEnum.GROUPON.getType(), "不是团购套餐类型的订单：" + tradeNo);
            bizType = GiftBizType.GROUPON_PACKAGE;
            bizOrderId = order.getId();
        } else if (tradeNo.startsWith(GROUPON_PACKAGE_ORDER_NO_PREFIX)) {
            GrouponOrderVO order = appGrouponOrderService.getByTradeNo(tradeNo);
            Assertions.notNull(order, "未获取到团购订单信息：" + tradeNo);
            bizType = GiftBizType.GROUPON_PACKAGE;
            bizOrderId = order.getId();
        } else {
            throw new KnownServiceException("交易单号无效，不是赠品活动类型的订单");
        }
        boolean exists = giftRecordMapper.exists(userId, bizType, bizOrderId);
        Assertions.isFalse(exists, "用户下单已获得过该赠品");
        List<GiftActivity> giftActivities = giftActivityMapper.selectByIds(giftActivityIds);
        Assertions.notEmpty(giftActivities, "赠品活动不存在");
        List<GiftRecord> list = new ArrayList<>(giftActivityIds.size());
        for (GiftActivity giftActivity : giftActivities) {
            if (!Boolean.TRUE.equals(giftActivity.getValid())) {
                log.warn("用户 {} 领取赠品活动 {} 未生效或已作废，忽略赠品发放", userId, giftActivity.getId());
                continue;
            }
            long receivedCount = giftRecordMapper.selectReceivedCountByUserIdAndGiftActivityId(userId, giftActivity.getId());
            if (giftActivity.getTakeLimitCount() > 0 && receivedCount >= giftActivity.getTakeLimitCount()) {
                log.warn("用户 {} 领取赠品活动 {} 领取数量 {} 超过上限 {}，忽略赠品发放", userId, giftActivity.getId(), receivedCount, giftActivity.getTakeLimitCount());
                continue;
            }
            GiftRecord entity = new GiftRecord();
            entity.setUserId(userId);
            entity.setShopId(giftActivity.getShopId());
            entity.setGiftActivityId(giftActivity.getId());
            entity.setGiftActivitySnapshot(JsonUtils.toJsonString(GiftActivityConvert.INSTANCE.convert(giftActivity)));
            entity.setGiftType(giftActivity.getType());
            entity.setSpuId(giftActivity.getSpuId());
            entity.setSkuId(giftActivity.getSkuId());
            entity.setCouponTemplateId(giftActivity.getCouponTemplateId());
            entity.setBizType(bizType.getValue());
            entity.setBizId(bizOrderId);
            entity.setStatus(GiftRecordStatus.PENDING.getValue());
            entity.setTradeNo(tradeNo);
            entity.setOriginPrice(Math.max(0, giftActivity.getOriginPrice()));
            entity.setCostPrice(Math.max(0, giftActivity.getCostPrice()));
            entity.setExpireTime(giftActivity.getEndTime());
            list.add(entity);
        }
        Boolean batch = giftRecordMapper.insertBatch(list);
        if (!Boolean.TRUE.equals(batch)) {
            return false;
        }
        autoTakeCouponAsync(userId, list);
        return true;
    }

    @Async
    public void autoTakeCouponAsync(Long userId, List<GiftRecord> list) {
        for (GiftRecord entity : list) {
            if (!Objects.equals(entity.getGiftType(), GiftGiveType.COUPON_TEMPLATE.getValue())) {
                continue;
            }
            // 自动领取优惠券
            AppGiftTakeDTO param = new AppGiftTakeDTO();
            param.setId(entity.getId());
            SpringUtil.getBean(CoreGiftRecordServiceImpl.class).take(userId, param);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean take(Long userId, AppGiftTakeDTO param) {
        GiftRecord giftRecord = giftRecordMapper.selectByUserIdAndId(userId, param.getId());
        Assertions.notNull(giftRecord, "赠品记录不存在");
        GiftActivity giftActivity = giftActivityMapper.selectById(giftRecord.getGiftActivityId());
        Assertions.notNull(giftActivity, "赠品活动不存在");
        Assertions.equals(GiftRecordStatus.PENDING.getValue(), giftRecord.getStatus(), "赠品【%s】不是待领取状态".formatted(giftActivity.getName()));
        GiftRecord updateObj = new GiftRecord();
        updateObj.setId(giftRecord.getId());
        updateObj.setStatus(GiftRecordStatus.TAKEN.getValue());
        updateObj.setTakeTime(LocalDateTime.now());
        if (Objects.equals(GiftGiveType.COUPON_TEMPLATE.getValue(), giftRecord.getGiftType())) {
            // 需要领取线上优惠券
            CouponTemplateDO couponTemplate = couponTemplateService.getCouponTemplate(giftRecord.getCouponTemplateId());
            Assertions.notNull(couponTemplate, "要领取的优惠券模板不存在：#" + giftRecord.getCouponTemplateId());
            couponRecordService.takeCoupon(couponTemplate, Set.of(userId), CouponTakeTypeEnum.GIFT_ACTIVITY);
            if (Objects.equals(couponTemplate.getDiscountType(), PromotionDiscountTypeEnum.PRICE.getType())) {
                updateObj.setOriginPrice(couponTemplate.getDiscountPrice());
            } else if (Objects.equals(couponTemplate.getDiscountType(), PromotionDiscountTypeEnum.PERCENT.getType())) {
                updateObj.setOriginPrice(couponTemplate.getDiscountLimitPrice());
            } else {
                updateObj.setOriginPrice(0);
            }
            if (CouponTemplateValidityTypeEnum.DATE.getType().equals(couponTemplate.getValidityType())) {
                updateObj.setExpireTime(couponTemplate.getValidEndTime());
            } else {
                updateObj.setExpireTime(LocalDateTime.now().plusDays(couponTemplate.getFixedEndTerm()));
            }
        } else {
            // 需要兑换线上或线下产品
            GiftTradeOrderSaveDTO saveDTO = new GiftTradeOrderSaveDTO();
            saveDTO.setShopId(giftActivity.getShopId());
            saveDTO.setName(giftActivity.getName());
            saveDTO.setPicUrl(giftActivity.getPicUrl());
            if (Objects.equals(GiftGiveType.ONLINE_PRODUCT.getValue(), giftActivity.getType())) {
                Assertions.notNull(param.getAddressId(), "领取线上产品类型的赠品，需要提供收货地址");
                saveDTO.setDeliveryType(DeliveryTypeEnum.EXPRESS.getType());
                saveDTO.setAddressId(param.getAddressId());
            } else {
                saveDTO.setDeliveryType(DeliveryTypeEnum.VERIFY.getType());
            }
            saveDTO.setSkuId(giftActivity.getSkuId());
            saveDTO.setCount(1);
            saveDTO.setOriginPrice(giftActivity.getOriginPrice());
            saveDTO.setCostPrice(giftActivity.getCostPrice());
            tradeOrderApi.createGiftTradeOrder(userId, saveDTO);
        }
        boolean b = giftRecordMapper.updateById(updateObj) > 0;
        if (b && Objects.equals(GiftGiveType.ONLINE_PRODUCT.getValue(), giftActivity.getType())
            && giftActivity.getCostPrice() > 0) {
            // 线上产品类型的赠品若有成本，需要给所属商家分账
            giftProducer.sendOnlineProductGiftTakeMessage(giftRecord.getShopId(), giftRecord.getTradeNo(), giftActivity.getCostPrice());
        }
        return b;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean transfer(Long userId, AppGiftTransferDTO param) {
        GiftRecord giftRecord = giftRecordMapper.selectByUserIdAndId(userId, param.getId());
        Assertions.notNull(giftRecord, "赠品不存在");
        Assertions.isTrue(Objects.equals(giftRecord.getStatus(), GiftRecordStatus.PENDING.getValue()), "赠品不是待领取状态，不支持转赠");
        UserSimpleVO userSimpleVO = memberUserApi.getUserByMobile(param.getMobile());
        Assertions.notNull(userSimpleVO, "用户不存在：" + param.getMobile());
        GiftRecord updateObj = new GiftRecord();
        updateObj.setId(giftRecord.getId());
        updateObj.setStatus(GiftRecordStatus.TRANSFERRED.getValue());
        updateObj.setTransferTime(LocalDateTime.now());
        giftRecordMapper.updateById(updateObj);
        GiftRecord transfer = GiftRecordConvert.INSTANCE.copy(giftRecord);
        transfer.setUserId(userSimpleVO.getId());
        transfer.setBizType(GiftBizType.FRIEND_TRANSFER.getValue());
        transfer.setBizId(userId);
        transfer.setStatus(GiftRecordStatus.PENDING.getValue());
        transfer.setTakeTime(LocalDateTime.now());
        return giftRecordMapper.insert(transfer) > 0;
    }

    @Override
    public int expire() {
        // 1. 查询已过期的赠品
        List<GiftRecord> list = giftRecordMapper.selectListByStatusAndExpireTimeLe(
                GiftRecordStatus.PENDING.getValue(), LocalDateTime.now());
        if (CollUtil.isEmpty(list)) {
            return 0;
        }
        // 2. 遍历执行
        int count = 0;
        for (GiftRecord giftRecord : list) {
            try {
                boolean success = expire(giftRecord);
                if (success) {
                    count++;
                }
            } catch (Exception e) {
                log.error("[expire][giftRecord({}) 更新为已过期失败]", giftRecord.getId(), e);
            }
        }
        return count;
    }

    /**
     * 过期单个赠品
     *
     * @param data 优惠劵
     * @return 是否过期成功
     */
    private boolean expire(GiftRecord data) {
        // 更新记录状态
        GiftRecord record = new GiftRecord();
        record.setStatus(GiftRecordStatus.EXPIRED.getValue());
        int updateRows = giftRecordMapper.updateByIdAndStatus(data.getId(), GiftRecordStatus.PENDING.getValue(), record);
        if (updateRows == 0) {
            log.error("[expire][giftRecord({}) 更新为已过期失败]", data.getId());
            return false;
        }
        log.info("[expire][giftRecord({}) 更新为已过期成功]", data.getId());
        return true;
    }

}